﻿using System;
using System.Collections.Generic;
using System.Data;
using System.Windows.Forms;

namespace Useful.GUI
{
    public class TreeViewHelper
    {
        private readonly string order = null;
        private readonly string idName = null;
        private readonly string masterIdName = null;
        private readonly string nodeName = null;
        private readonly TreeView tree = null;

        private readonly DataTable table = null;

        public TreeViewHelper(DataView view, TreeView tree, string idName, string masterIdName, string nodeName)
        {
            this.tree = tree;
            this.order = view.Sort;
            this.idName = idName;
            this.masterIdName = masterIdName;
            this.nodeName = nodeName;
            this.table = view.ToTable();
        }

        public DataTable CreateTree()
        {
            CreateTree(tree.Nodes);

            return this.table;
        }

        private void CreateTree(TreeNodeCollection nodes)
        {
            nodes.Clear();

            List<DataRow> rootRows = FindRootRows();

            foreach (DataRow row in rootRows)
            {
                TreeNode node = CreateNode(row, nodes);

                CreateSubTree(node.Nodes, row);
            }
        }

        private TreeNode CreateNode(DataRow row, TreeNodeCollection nodes)
        {
            TreeNode newNode = nodes.Add(row[idName].ToString(), row[nodeName].ToString());
            newNode.Tag = row;

            return newNode;
        }

        private void CreateSubTree(TreeNodeCollection nodes, DataRow rootRow)
        {
            List<DataRow> slaveRows = FindSlaveRows(rootRow);

            foreach (DataRow row in slaveRows)
            {
                TreeNode node = CreateNode(row, nodes);

                CreateSubTree(node.Nodes, row);
            }
        }

        private DataRow[] SelectRows(string filter)
        {
            return table.Select(filter, order);
        }

        private List<DataRow> FindSlaveRows(DataRow rootRow)
        {
            DataRow[] rows = SelectRows(masterIdName + " = " + rootRow[idName]);

            List<DataRow> res = new List<DataRow>();

            AddRows(res, rows);

            return res;
        }

        private static void AddRows(List<DataRow> list, IEnumerable<DataRow> rows)
        {
            list.AddRange(rows);
        }

        private List<DataRow> FindRootRows()
        {
            List<DataRow> res = new List<DataRow>();

            foreach (DataRow row in table.Rows)
            {
                if (row[masterIdName] != null && row[masterIdName] != DBNull.Value)
                {
                    DataRow[] dr = SelectRows(idName + " = " + row[masterIdName]);

                    if (dr.Length == 0)
                        res.Add(row);
                }
            }

            DataRow[] drs = SelectRows(masterIdName + " IS NULL");
            AddRows(res, drs);

            return res;
        }
    }
}
